﻿#region using
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Collections;
using System.Threading;
using System.Runtime.InteropServices;
#endregion using

//dodelat dynamicky setter pro SetArrayItem
namespace Jsil.Runtime
{
#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	public static class RuntimeMethods
	{
		#region fields/ctors
		static RuntimeMethods()
		{
			RuntimeMethodsExtender=new NullRuntimeMethodsExtender();
		}

		public static IRuntimeMethodsExtender RuntimeMethodsExtender {get;set;}
		#endregion fields/ctors

		#region math op,Equals,EqualsStrictly,Compare,Debug
		public static object Add(object x, object y)
		{
			if ((x is string) || (y is string))
				return x.ToString() + y.ToString();

			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2+((int)y);*/
				if (ty==typeof(uint))
					return x2+((uint)y);
				/*if (ty==typeof(long))
					return x2+((long)y);*/
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				/*if (ty==typeof(short))
					return x2+((short)y);*/
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				/*if (ty==typeof(decimal))
					return x2+((decimal)y);*/
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				if (ty==typeof(short))
					return x2+((short)y);
				/*if (ty==typeof(double))
					return x2+((double)y);*/
				if (ty==typeof(byte))
					return x2+((byte)y);
				if (ty==typeof(decimal))
					return x2+((decimal)y);
				/*if (ty==typeof(Single))
					return x2+((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2+((int)y);
				if (ty==typeof(uint))
					return x2+((uint)y);
				if (ty==typeof(long))
					return x2+((long)y);
				if (ty==typeof(ulong))
					return x2+((ulong)y);
				if (ty==typeof(short))
					return x2+((short)y);
				if (ty==typeof(double))
					return x2+((double)y);
				if (ty==typeof(byte))
					return x2+((byte)y);
				/*if (ty==typeof(decimal))
					return x2+((decimal)y);*/
				if (ty==typeof(Single))
					return x2+((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static object Sub(object x, object y)
		{
			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				/*if (ty==typeof(ulong))
					return x2-((ulong)y);*/
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				/*if (ty==typeof(ulong))
					return x2-((ulong)y);*/
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2-((int)y);*/
				if (ty==typeof(uint))
					return x2-((uint)y);
				/*if (ty==typeof(long))
					return x2-((long)y);*/
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				/*if (ty==typeof(short))
					return x2-((short)y);*/
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				/*if (ty==typeof(ulong))
					return x2-((ulong)y);*/
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				/*if (ty==typeof(decimal))
					return x2-((decimal)y);*/
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				if (ty==typeof(short))
					return x2-((short)y);
				/*if (ty==typeof(double))
					return x2-((double)y);*/
				if (ty==typeof(byte))
					return x2-((byte)y);
				if (ty==typeof(decimal))
					return x2-((decimal)y);
				/*if (ty==typeof(Single))
					return x2-((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2-((int)y);
				if (ty==typeof(uint))
					return x2-((uint)y);
				if (ty==typeof(long))
					return x2-((long)y);
				if (ty==typeof(ulong))
					return x2-((ulong)y);
				if (ty==typeof(short))
					return x2-((short)y);
				if (ty==typeof(double))
					return x2-((double)y);
				if (ty==typeof(byte))
					return x2-((byte)y);
				/*if (ty==typeof(decimal))
					return x2-((decimal)y);*/
				if (ty==typeof(Single))
					return x2-((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static object Mul(object x,object y)
		{
			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				/*if (ty==typeof(ulong))
					return x2*((ulong)y);*/
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				/*if (ty==typeof(ulong))
					return x2*((ulong)y);*/
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2*((int)y);*/
				if (ty==typeof(uint))
					return x2*((uint)y);
				/*if (ty==typeof(long))
					return x2*((long)y);*/
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				/*if (ty==typeof(short))
					return x2*((short)y);*/
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				/*if (ty==typeof(ulong))
					return x2*((ulong)y);*/
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				/*if (ty==typeof(decimal))
					return x2*((decimal)y);*/
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				if (ty==typeof(short))
					return x2*((short)y);
				/*if (ty==typeof(double))
					return x2*((double)y);*/
				if (ty==typeof(byte))
					return x2*((byte)y);
				if (ty==typeof(decimal))
					return x2*((decimal)y);
				/*if (ty==typeof(Single))
					return x2*((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2*((int)y);
				if (ty==typeof(uint))
					return x2*((uint)y);
				if (ty==typeof(long))
					return x2*((long)y);
				if (ty==typeof(ulong))
					return x2*((ulong)y);
				if (ty==typeof(short))
					return x2*((short)y);
				if (ty==typeof(double))
					return x2*((double)y);
				if (ty==typeof(byte))
					return x2*((byte)y);
				/*if (ty==typeof(decimal))
					return x2*((decimal)y);*/
				if (ty==typeof(Single))
					return x2*((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static object Div(object x,object y)
		{
			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				/*if (ty==typeof(ulong))
					return x2/((ulong)y);*/
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				/*if (ty==typeof(ulong))
					return x2/((ulong)y);*/
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2/((int)y);*/
				if (ty==typeof(uint))
					return x2/((uint)y);
				/*if (ty==typeof(long))
					return x2/((long)y);*/
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				/*if (ty==typeof(short))
					return x2/((short)y);*/
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				/*if (ty==typeof(ulong))
					return x2/((ulong)y);*/
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				/*if (ty==typeof(decimal))
					return x2/((decimal)y);*/
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				if (ty==typeof(short))
					return x2/((short)y);
				/*if (ty==typeof(double))
					return x2/((double)y);*/
				if (ty==typeof(byte))
					return x2/((byte)y);
				if (ty==typeof(decimal))
					return x2/((decimal)y);
				/*if (ty==typeof(Single))
					return x2/((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2/((int)y);
				if (ty==typeof(uint))
					return x2/((uint)y);
				if (ty==typeof(long))
					return x2/((long)y);
				if (ty==typeof(ulong))
					return x2/((ulong)y);
				if (ty==typeof(short))
					return x2/((short)y);
				if (ty==typeof(double))
					return x2/((double)y);
				if (ty==typeof(byte))
					return x2/((byte)y);
				/*if (ty==typeof(decimal))
					return x2/((decimal)y);*/
				if (ty==typeof(Single))
					return x2/((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static object Rem(object x,object y)
		{
			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				/*if (ty==typeof(ulong))
					return x2%((ulong)y);*/
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				/*if (ty==typeof(ulong))
					return x2%((ulong)y);*/
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2%((int)y);*/
				if (ty==typeof(uint))
					return x2%((uint)y);
				/*if (ty==typeof(long))
					return x2%((long)y);*/
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				/*if (ty==typeof(short))
					return x2%((short)y);*/
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				/*if (ty==typeof(ulong))
					return x2%((ulong)y);*/
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				/*if (ty==typeof(decimal))
					return x2%((decimal)y);*/
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				if (ty==typeof(short))
					return x2%((short)y);
				/*if (ty==typeof(double))
					return x2%((double)y);*/
				if (ty==typeof(byte))
					return x2%((byte)y);
				if (ty==typeof(decimal))
					return x2%((decimal)y);
				/*if (ty==typeof(Single))
					return x2%((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2%((int)y);
				if (ty==typeof(uint))
					return x2%((uint)y);
				if (ty==typeof(long))
					return x2%((long)y);
				if (ty==typeof(ulong))
					return x2%((ulong)y);
				if (ty==typeof(short))
					return x2%((short)y);
				if (ty==typeof(double))
					return x2%((double)y);
				if (ty==typeof(byte))
					return x2%((byte)y);
				/*if (ty==typeof(decimal))
					return x2%((decimal)y);*/
				if (ty==typeof(Single))
					return x2%((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static new bool Equals(object x, object y)
		{
			bool xNull=x==null;
			bool yNull=y==null;
			if (xNull&&yNull)
				return true;
			if (xNull||yNull)
				return false;

			if ((x is string)||(y is string))
				return x.ToString()==y.ToString();
			
			if (x.Equals(y))
				return true;

			Type tx=x.GetType();
			Type ty=y.GetType();
			#region by type
			if (tx==typeof(int))
			{
				int x2=(int)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(uint))
			{
				uint x2=(uint)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(long))
			{
				long x2=(long)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(ulong))
			{
				ulong x2=(ulong)x;
				/*if (ty==typeof(int))
					return x2+((int)y);*/
				if (ty==typeof(uint))
					return x2==((uint)y);
				/*if (ty==typeof(long))
					return x2+((long)y);*/
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				/*if (ty==typeof(short))
					return x2+((short)y);*/
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(short))
			{
				short x2=(short)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				/*if (ty==typeof(ulong))
					return x2+((ulong)y);*/
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(double))
			{
				double x2=(double)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				/*if (ty==typeof(decimal))
					return x2+((decimal)y);*/
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(byte))
			{
				byte x2=(byte)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			if (tx==typeof(decimal))
			{
				decimal x2=(decimal)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				if (ty==typeof(short))
					return x2==((short)y);
				/*if (ty==typeof(double))
					return x2+((double)y);*/
				if (ty==typeof(byte))
					return x2==((byte)y);
				if (ty==typeof(decimal))
					return x2==((decimal)y);
				/*if (ty==typeof(Single))
					return x2+((Single)y);*/
			}
			if (tx==typeof(Single))
			{
				Single x2=(Single)x;
				if (ty==typeof(int))
					return x2==((int)y);
				if (ty==typeof(uint))
					return x2==((uint)y);
				if (ty==typeof(long))
					return x2==((long)y);
				if (ty==typeof(ulong))
					return x2==((ulong)y);
				if (ty==typeof(short))
					return x2==((short)y);
				if (ty==typeof(double))
					return x2==((double)y);
				if (ty==typeof(byte))
					return x2==((byte)y);
				/*if (ty==typeof(decimal))
					return x2+((decimal)y);*/
				if (ty==typeof(Single))
					return x2==((Single)y);
			}
			#endregion by type
			throw new InvalidOperationException();
		}

		public static bool EqualsStrictly(object x, object y)
		{
			return Marshal.ReferenceEquals(x,y);
		}

		static readonly Type _doubleType=typeof(double);
		public static int Compare(object x,object y)
		{
			Type tx=x.GetType();
			if ((tx==y.GetType())&&(x is IComparable))
				return ((IComparable)x).CompareTo(y);
			if ((TypeConverter.ConvertTryConvert(ref x,_doubleType))&&(TypeConverter.ConvertTryConvert(ref y,_doubleType)))
				return ((double)x).CompareTo((double)y);
			throw new RuntimeException(RuntimeExceptionReason.Compare);
		}

#if !DebugRuntime
		[DebuggerHidden]
#endif
		public static object Debug()
		{
			if (Debugger.Launch())
				Debugger.Break();
			return null;
		}
		#endregion math op,Equals,EqualsStrictly,Compare,Debug

		#region GetMember
		static readonly object[] _emptyObjectArray=new object[0];
		internal static readonly Type _objectType=typeof(object);
		internal static readonly Type _typeType=typeof(Type);
		public static object GetMember(GlobalObject instance,object objectVar,string memberName)
		{
			object objectVarWrap;
			if (objectVar is ExternalLibraryObject)
			{
				ExternalLibraryObject elo=((ExternalLibraryObject)objectVar);
				if (objectVar is NamespaceObject)
					memberName=((NamespaceObject)objectVar)._name+"."+memberName;
				Type t=elo._assembly.GetType(memberName);
				return t==null?(object)new NamespaceObject() { _assembly=elo._assembly,_name=memberName }:(object)new StaticObject() { Type=t };
			}
			
			MemberInfo[] mis;
			Type objectVarType;
			if (objectVar is StaticObject)
			{
				objectVarWrap=null;
				objectVarType=((StaticObject)objectVar).Type;
				mis=objectVarType.GetMember(memberName,BindingFlags.Public|BindingFlags.Static);
			}
			else
			{
				objectVarWrap=GetJsWrapper(objectVar);
				objectVarType=objectVarWrap.GetType();
				mis=objectVarType.GetMember(memberName,BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static);
			}
			if (mis.Length==0)
				throw new RuntimeException(RuntimeExceptionReason.NoMemberOnExternalVariable,(objectVar is StaticObject?objectVarType:objectVar.GetType()).Name,memberName);

			MemberInfo mmi=mis[0];
			MethodInfo mi=mmi as MethodInfo;
			if (mi==null)
			{
				Func<object> result=CreateGetMethodWithTarget(mmi,objectVarWrap);
				return result();
			}
			else
				return new ExternalMethodInfo() { Target=objectVarWrap,Type=objectVarType,MethodName=memberName };
		}

		#region CreateGetMethod/WithTarget
		//http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
		static Type[] _createGetMethodArgs=new Type[] { _objectType };
		static Dictionary<MemberInfo,DynamicMethod> _createGetMethodCache=new Dictionary<MemberInfo,DynamicMethod>();
		private static DynamicMethod CreateGetMethod(MemberInfo member)
		{
			DynamicMethod result;
			if (_createGetMethodCache.TryGetValue(member,out result))
				return result;

			PropertyInfo pi=member as PropertyInfo;
			FieldInfo fi=pi==null?member as FieldInfo:null;
			MemberInfo mi=(MemberInfo)member;
			bool instanceHolder=!(pi==null?fi.IsStatic:pi.GetGetMethod().IsStatic);
			bool isProp=fi==null;
			Type memberType=isProp?pi.PropertyType:fi.FieldType;
			Type declaringType=mi.DeclaringType;
			result=new DynamicMethod(declaringType.AssemblyQualifiedName+"_Get"+mi.Name,_objectType,_createGetMethodArgs,true);
			_createGetMethodCache.Add(member,result);

			ILGenerator gen=result.GetILGenerator();
			if (instanceHolder)
			{
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Castclass,declaringType);
			}
			if (isProp)
				gen.Emit(instanceHolder?OpCodes.Callvirt:OpCodes.Call,pi.GetGetMethod());
			else
				gen.Emit(instanceHolder?OpCodes.Ldfld:OpCodes.Ldsfld,fi);
			if (memberType.IsValueType)
				gen.Emit(OpCodes.Box,memberType);
			gen.Emit(OpCodes.Ret);
			return result;
		}

		private static Func<object> CreateGetMethodWithTarget(MemberInfo member,object target)
		{
			return (Func<object>)CreateGetMethod(member).CreateDelegate(typeof(Func<object>),target);
		}
		#endregion CreateGetMethod/WithTarget
		#endregion GetMember

		#region SetMember
		public static void SetMember(GlobalObject instance,object objectVar,string memberName,object value)
		{
			//object objectVarWrap=GetJsWrapper(objectVar);
			object objectVarWrap=objectVar;

			MemberInfo[] mis=objectVarWrap.GetType().GetMember(memberName,BindingFlags.Public|BindingFlags.Instance);
			if (mis.Length==0)
				throw new RuntimeException(RuntimeExceptionReason.NoMemberOnExternalVariable,objectVar.GetType().Name,memberName);
			MemberInfo mmi=mis[0];
			if (mmi is MethodInfo)
				throw new RuntimeException(RuntimeExceptionReason.NoMemberOnExternalVariable,objectVar.GetType().Name,memberName);

			Action<object> result=CreateSetMethodWithTarget(mmi,objectVarWrap);
			result(value);
		}

		#region CreateSetMethod/WithTarget
		static Type[] _createSetMethodArgs=new Type[] { _objectType,_objectType };
		static MethodInfo _converter=typeof(Convert).GetMethod("ChangeType",BindingFlags.Public|BindingFlags.Static,null,new Type[] { _objectType,_typeType },null);
		static MethodInfo _getTypeFromHandle=_typeType.GetMethod("GetTypeFromHandle");
		static Dictionary<MemberInfo,DynamicMethod> _createSetMethodCache=new Dictionary<MemberInfo,DynamicMethod>();
		private static DynamicMethod CreateSetMethod(MemberInfo member)
		{
			DynamicMethod result;
			if (_createSetMethodCache.TryGetValue(member,out result))
				return result;

			PropertyInfo pi=member as PropertyInfo;
			FieldInfo fi=pi==null?member as FieldInfo:null;
			MemberInfo mi=(MemberInfo)member;
			bool isProp=fi==null;
			Type memberType=isProp?pi.PropertyType:fi.FieldType;
			Type declaringType=mi.DeclaringType;
			result=new DynamicMethod(declaringType.AssemblyQualifiedName+"_Set"+mi.Name,typeof(void),_createSetMethodArgs,true);
			_createSetMethodCache.Add(member,result);

			ILGenerator gen=result.GetILGenerator();
			gen.Emit(OpCodes.Ldarg_0);
			gen.Emit(OpCodes.Castclass,declaringType);
			gen.Emit(OpCodes.Ldarg_1);
			if (memberType.IsValueType)
			{
				gen.Emit(OpCodes.Ldtoken,memberType);
				gen.Emit(OpCodes.Call,_getTypeFromHandle);
				gen.Emit(OpCodes.Call,_converter);
				gen.Emit(OpCodes.Unbox_Any,memberType);
			}
			else
				gen.Emit(OpCodes.Castclass,memberType);

			if (isProp)
				gen.Emit(OpCodes.Callvirt,pi.GetSetMethod());
			else
				gen.Emit(OpCodes.Stfld,fi);
			gen.Emit(OpCodes.Ret);
			return result;
		}

		private static Action<object> CreateSetMethodWithTarget(MemberInfo member,object target)
		{
			DynamicMethod setter=CreateSetMethod(member);
			return (Action<object>)setter.CreateDelegate(typeof(Action<object>),target);
		}
		#endregion CreateSetMethod/WithTarget
		#endregion SetMember

		#region GetExternalLibrary
		public static object GetExternalLibrary(FunctionObjectBase instance,string alias)
		{
			instance=GetExternalLibrary_GetRootInstance(instance);
			IDictionary<string,object> libs=instance.ExternalLibraries;
			object result;
			if (!libs.TryGetValue(alias,out result))
			{
				string predefinition;
				instance._predefinedImports.TryGetValue(alias,out predefinition);
				ResolveExternalLibraryEventArgs args=new ResolveExternalLibraryEventArgs() { LibraryName=alias,Predefinition=predefinition };
				//instance.FireResolveExternalLibrary(args);
				if (instance.ResolveExternalLibrary!=null)
					instance.ResolveExternalLibrary(instance,args);
				object library=args.Assembly;
				Assembly asm=library is string?Assembly.LoadFrom((string)library):library as Assembly;
				if (asm==null)
					throw new RuntimeException(RuntimeExceptionReason.CantResolveLibrary,new object[] { alias,predefinition });
				result=new ExternalLibraryObject() { _assembly=asm };

				Type type=asm.GetType("MyType");
				if (type!=null)
				{
					MethodInfo mi=type.GetMethod("Main",BindingFlags.Public|BindingFlags.Instance);
					if (mi!=null)
					{
						Type bType=type.BaseType;
						if (bType!=null)
						{
							bType=bType.BaseType;
							if (bType!=null)
							{
								FieldInfo fi=bType.GetField("_parentContext",BindingFlags.NonPublic|BindingFlags.Instance);
								if (fi!=null)
								{
									object global=Activator.CreateInstance(type);
									fi.SetValue(global,instance);
									mi.Invoke(global,new object[0]);
									result=global;
								}
							}
						}
					}
				}
				libs.Add(alias,result);
			}

			return result;
		}

		static FunctionObjectBase GetExternalLibrary_GetRootInstance(FunctionObjectBase instance)
		{
			FunctionObjectBase par;
			while (true)
			{
				par=instance.GetParentContext();
				if (par==null)
					return instance;
				instance=par;
			}
		}
		#endregion GetExternalLibrary

		#region GetArrayItem/SetArrayItem
		public static object GetArrayItem(object array,object index)
		{
			if (array is ArrayObject)
				return ((ArrayObject)array).GetItem(index);

			object result;
			if (RuntimeMethodsExtender.GetArrayItem(array,index,out result))
				return result;

			Type arrayType=array.GetType();
			if ((typeof(IList).IsAssignableFrom(arrayType))&&(TypeConverter.ConvertTryConvert(ref index,typeof(int))))
				return ((IList)array)[(int)index];
			if (typeof(IDictionary).IsAssignableFrom(arrayType))
				return ((IDictionary)array)[index];
			if (index!=null)
			{
				object objectVar=array.GetType();
				Type indexType=index.GetType();

				PropertyInfo[] pis=Array.FindAll(arrayType.GetProperties(BindingFlags.Public|BindingFlags.Instance),item=>item.Name=="Item");
				foreach (PropertyInfo item in pis)
				{
					Type t=item.GetIndexParameters()[0].ParameterType;
					MethodInfo indexConvertMethod;
					if (TypeConverter.GetConvertMethod(indexType,t,out indexConvertMethod))
					{
						Func<object,object,object> res=(Func<object,object,object>)CreateGetMethodWithIndex(item,indexType,indexConvertMethod).CreateDelegate(typeof(Func<object,object,object>));
						return res(array,index);
					}
				}
			}
			throw new RuntimeException(RuntimeExceptionReason.UnknownArrayType);
		}

		#region CreateGetMethodWithIndex
		//http://jachman.wordpress.com/2006/08/22/2000-faster-using-dynamic-method-calls/
		static Type[] _createGetMethodArgsWithIndex=new Type[] { _objectType,_objectType };
		private static DynamicMethod CreateGetMethodWithIndex(PropertyInfo member,Type indexType,MethodInfo indexConvertMethod)
		{
			DynamicMethod result;
			if (_createGetMethodCache.TryGetValue(member,out result))
				return result;

			PropertyInfo pi=member;
			MemberInfo mi=member;
			bool instanceHolder=!pi.GetGetMethod().IsStatic;
			Type memberType=pi.PropertyType;
			Type declaringType=mi.DeclaringType;
			result=new DynamicMethod(declaringType.AssemblyQualifiedName+"_Get"+mi.Name,_objectType,_createGetMethodArgsWithIndex,true);
			_createGetMethodCache.Add(member,result);

			ILGenerator gen=result.GetILGenerator();
			if (instanceHolder)
			{
				gen.Emit(OpCodes.Ldarg_0);
				gen.Emit(OpCodes.Castclass,declaringType);
			}

			gen.Emit(OpCodes.Ldarg_1);
			gen.Emit(OpCodes.Castclass,indexType);

			if (indexConvertMethod!=null)
				gen.Emit(OpCodes.Call,indexConvertMethod);
			gen.Emit(instanceHolder?OpCodes.Callvirt:OpCodes.Call,pi.GetGetMethod());
			if (memberType.IsValueType)
				gen.Emit(OpCodes.Box,memberType);
			gen.Emit(OpCodes.Ret);
			return result;
		}
		#endregion CreateGetMethodWithIndex

		public static void SetArrayItem(object array,object index,object item)
		{
			if (array is ArrayObject)
			{
				((ArrayObject)array).SetItem(index,item);
				return;
			}

			if (RuntimeMethodsExtender.SetArrayItem(array,index,item))
				return;

			Type arrayType=array.GetType();
			if ((typeof(IList).IsAssignableFrom(arrayType))&&(TypeConverter.ConvertTryConvert(ref index,typeof(int))))
			{
				((IList)array)[(int)index]=item;
				return;
			}
			if (typeof(IDictionary).IsAssignableFrom(array.GetType()))
			{
				((IDictionary)array)[index]=item;
				return;
			}
			throw new RuntimeException(RuntimeExceptionReason.UnknownArrayType);
		}
		#endregion GetArrayItem/SetArrayItem

		#region GetJsWrapper
		static object GetJsWrapper(object value)
		{
			Type t=value.GetType();
			if (t==typeof(string))
				return new StringObject((string)value);
			if (t==typeof(DateTime))
				return new DateObject((DateTime)value);
			if ((typeof(IList).IsAssignableFrom(t))&&(!typeof(ArrayObject).IsAssignableFrom(t)))
				return new ArrayObjectLateBinding((IList)value);
			return value;
		}
		#endregion GetJsWrapper

		#region GetFuncType/GetPropMethodFuncType/GetDelegateMethodCall
		static Dictionary<int,Type> _getFuncTypeCache=new Dictionary<int,Type>();
		static string _thisAsmFullName=typeof(Func<>).Assembly.FullName;
		public static Type GetFuncType(int parmsCount)
		{
			Type result;
			if (!_getFuncTypeCache.TryGetValue(parmsCount,out result))
			{
				StringBuilder sb=new StringBuilder("System.Func`").Append(parmsCount+1).Append('[');
				sb.Insert(sb.Length,"[System.Object],",parmsCount);
				sb.Append("[System.Object]]");
				//if (Environment.Version.Major==2)
					sb.Append(", ").Append(_thisAsmFullName);
				result=Type.GetType(sb.ToString());
				_getFuncTypeCache.Add(parmsCount,result);
			}
			return result;
		}

		static Dictionary<Type,Type> _getPropMethodFuncTypeCache=new Dictionary<Type,Type>();
		public static Type GetPropMethodFuncType(Type propertyInfoType)
		{
			Type result;
			if (!_getPropMethodFuncTypeCache.TryGetValue(propertyInfoType,out result))
			{
				StringBuilder sb=new StringBuilder("System.Func`1").Append('[');
				sb.Append("[").Append(propertyInfoType.FullName).Append("]]");
				//if (Environment.Version.Major==2)
					sb.Append(", ").Append(_thisAsmFullName);
				result=Type.GetType(sb.ToString());
				_getPropMethodFuncTypeCache.Add(propertyInfoType,result);
			}
			return result;
		}

		static Dictionary<Type,Type> _getPropMethodActionTypeCache=new Dictionary<Type,Type>();
		public static Type GetPropMethodActionType(Type propertyInfoType)
		{
			Type result;
			if (!_getPropMethodActionTypeCache.TryGetValue(propertyInfoType,out result))
			{
				StringBuilder sb=new StringBuilder("System.Action`1").Append('[');
				sb.Append("[").Append(propertyInfoType.FullName).Append("]]");
				//if (Environment.Version.Major==2)
				//	sb.Append(", ").Append(_thisAsmFullName);
				result=Type.GetType(sb.ToString());
				_getPropMethodActionTypeCache.Add(propertyInfoType,result);
			}
			return result;
		}

		public static MethodInfo GetDelegateMethodCall(int parmsCount)
		{
			return Array.Find(typeof(DynamDelCalls).GetMethods(),x => (x.Name=="Call")&&(x.GetParameters().Length==parmsCount+1));
		}

		public static MethodInfo GetDelegateConstuctor(int parmsCount)
		{
			return Array.Find(typeof(DynamDelCalls).GetMethods(),x => (x.Name=="Create")&&(x.GetParameters().Length==parmsCount+1));
		}
		#endregion GetFuncType/GetPropMethodFuncType/GetDelegateMethodCall

		#region MakeJsException
		public static JsError MakeJsError(Exception ex)
		{
			return new JsError(ex);
		}
		#endregion MakeJsException
	}

	#region RuntimeMethodsExtender
	public interface IRuntimeMethodsExtender
	{
		bool GetArrayItem(object array,object index,out object result);
		bool SetArrayItem(object array,object index,object item);
		bool DynamicCall(MethodInfo method,ParameterInfo[] pis,object target,object[] arguments,out object result);
	}

#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	class NullRuntimeMethodsExtender:IRuntimeMethodsExtender
	{
		public bool GetArrayItem(object array,object index,out object result)
		{
			result=null;
			return false;
		}

		public bool SetArrayItem(object array,object index,object item)
		{
			return false;
		}

		public bool DynamicCall(MethodInfo method,ParameterInfo[] pis,object target,object[] arguments,out object result)
		{
			result=null;
			return false;
		}
	}
	#endregion RuntimeMethodsExtender

	#region RuntimeException
#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	public class RuntimeException:Exception
	{
		public RuntimeException(RuntimeExceptionReason reason)
		{
			Reason = reason;
		}

		public RuntimeException(RuntimeExceptionReason reason, params object[] messageData):this(reason)
		{
			MessageData = messageData;
		}

		public RuntimeExceptionReason Reason { get; private set; }

		public object[] MessageData { get; private set; }

		public override string Message
		{
			get
			{
				switch (Reason)
				{
					case RuntimeExceptionReason.Compare:
						return "Can't compare values";
					case RuntimeExceptionReason.NoExternalVariable:
						return string.Format("There is no external variable \"{0}\" declared", MessageData);
					case RuntimeExceptionReason.NoMemberOnExternalVariable:
						return string.Format("There is no compatible member \"{1}\" on external variable \"{0}\"", MessageData);
					case RuntimeExceptionReason.NoPropertyOnExternalVariable:
						return string.Format("There is no compatible property \"{1}\" on external variable \"{0}\"", MessageData);
					case RuntimeExceptionReason.UnknownArrayType:
						return "Unknown array type - use extender";
					case RuntimeExceptionReason.NoCompatibleMethod:
						return string.Format("There is no compatible method \"{1}\" with {2} object parameters",MessageData);
					default:
						return "Unknown error";
				}
			}
		}
	}

	public enum RuntimeExceptionReason { Compare, NoExternalVariable, NoMemberOnExternalVariable, NoPropertyOnExternalVariable, UnknownArrayType, CantResolveLibrary, InternalError, NoCompatibleMethod }
	#endregion RuntimeException

	#region TypeConverters
#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	static class TypeConverter
	{
		static TypeConverter()
		{
			FindConvertMethods();
		}

		internal static bool ConvertTryConvert(ref object value,Type targetType)
		{
			if (value==null)
				return false;

			Type valueType=value.GetType();
			if ((targetType==valueType)||(targetType.IsAssignableFrom(valueType)))
				return true;

			Dictionary<Type,MethodInfo> part;
			MethodInfo mi;
			if ((!_convertMethods.TryGetValue(targetType,out part))||(!part.TryGetValue(valueType,out mi)))
				return false;

			value=mi.Invoke(null,new object[]{value});
			return true;
		}

		internal static bool GetConvertMethod(Type sourceType,Type targetType,out MethodInfo result)
		{
			result=null;
			if ((targetType==sourceType)||(targetType.IsAssignableFrom(sourceType)))
				return true;
			Dictionary<Type,MethodInfo> part;
			return ((_convertMethods.TryGetValue(targetType,out part))&&(part.TryGetValue(sourceType,out result)));
		}

		static Dictionary<Type,Dictionary<Type,MethodInfo>> _convertMethods=new Dictionary<Type,Dictionary<Type,MethodInfo>>();
		static void FindConvertMethods()
		{
			MethodInfo[] mis=typeof(Convert).GetMethods(BindingFlags.Public|BindingFlags.Static);
			foreach (MethodInfo mi in mis)
			{
				if (!mi.Name.StartsWith("To"))
					continue;
				Type type1=mi.ReturnType;
				if (!type1.IsValueType)
					continue;
				ParameterInfo[] parms=mi.GetParameters();
				if (parms.Length!=1)
					continue;
				Type type2=parms[0].ParameterType;
				if (!type2.IsValueType)
					continue;
				if (type1==type2)
					continue;

				Dictionary<Type,MethodInfo> part;
				if (!_convertMethods.TryGetValue(type1,out part))
				{
					part=new Dictionary<Type,MethodInfo>();
					_convertMethods.Add(type1,part);
				}
				part.Add(type2,mi);
			}
		}
	}
	#endregion TypeConverters

	#region DynamDelCalls
#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	public static class DynamDelCalls
	{
		#region call
		public static object Call(object method)
		{
			Func<object> f=CastToFunc<Func<object>>(method,0);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f();
			return DynamicCall(f.Method,pis,f.Target,new object[0]);
		}

		public static object Call(object method,object arg1)
		{
			Func<object,object> f=CastToFunc<Func<object,object>>(method,1);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1 });
		}

		public static object Call(object method,object arg1,object arg2)
		{
			Func<object,object,object> f=CastToFunc<Func<object,object,object>>(method,2);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3)
		{
			Func<object,object,object,object> f=CastToFunc<Func<object,object,object,object>>(method,3);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4)
		{
			Func<object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object>>(method,4);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4,object arg5)
		{
			Func<object,object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object,object>>(method,5);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4,arg5);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4,arg5 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6)
		{
			Func<object,object,object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object,object,object>>(method,6);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4,arg5,arg6);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4,arg5,arg6 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7)
		{
			Func<object,object,object,object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object,object,object,object>>(method,7);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4,arg5,arg6,arg7);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7,object arg8)
		{
			Func<object,object,object,object,object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object,object,object,object,object>>(method,8);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 });
		}

		public static object Call(object method,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7,object arg8,object arg9)
		{
			Func<object,object,object,object,object,object,object,object,object,object> f=CastToFunc<Func<object,object,object,object,object,object,object,object,object,object>>(method,9);
			ParameterInfo[] pis=f.Method.GetParameters();
			if ((f.Target is GlobalObject)||(HaveOnlyObjects(pis,f.Method.ReturnType)))
				return f(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9);
			return DynamicCall(f.Method,pis,f.Target,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9 });
		}

		static T CastToFunc<T>(object method,int parmsCount)
		{
			return method is ExternalMethodInfo?(T)ExternalMethodInfoToDelegate((ExternalMethodInfo)method,parmsCount):(T)method;
		}

		static object ExternalMethodInfoToDelegate(ExternalMethodInfo method,int parmsCount)
		{
			MethodInfo[] mis=method.Type.GetMethods(BindingFlags.Public|BindingFlags.Instance|BindingFlags.Static);
			mis=Array.FindAll(mis,x => x.Name==method.MethodName&&x.GetParameters().Length==parmsCount);
			MethodInfo mi=mis.Length==1
				?mi=mis[0]
				:mi=Array.Find(mis,item => !(Array.Exists(item.GetParameters(),item2 => item2.ParameterType!=RuntimeMethods._objectType)));
			if (mi==null)
				throw new RuntimeException(RuntimeExceptionReason.NoCompatibleMethod,method.Type,method.MethodName,parmsCount);
			return RuntimeMethods.GetFuncType(parmsCount).GetConstructors()[0].Invoke(new object[] { method.Target,mi.MethodHandle.GetFunctionPointer() });
		}

		public static object DynamicCall(MethodInfo method,ParameterInfo[] pis,object target,object[] arguments)
		{
			object result;
			if (RuntimeMethods.RuntimeMethodsExtender.DynamicCall(method,pis,target,arguments,out result))
				return result;

			//tady muzu vyresit rozdilny pocet argumentu zadanych a potrebnych
			for (int a=0;a<arguments.Length;a++)
				arguments[a]=TranslateType(pis[a],arguments[a]);
			return method.Invoke(target,arguments);
		}
		#endregion call

		#region create
		static object[] _emptyObjectArray=new object[0];
		public static object Create(Type type)
		{
			return CreateObject(type,_emptyObjectArray);
		}

		public static object Create(Type type,object arg1)
		{
			return CreateObject(type,new object[] { arg1 });
		}

		public static object Create(Type type,object arg1,object arg2)
		{
			return CreateObject(type,new object[] { arg1,arg2 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4,object arg5)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4,arg5 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4,arg5,arg6 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7,object arg8)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8 });
		}

		public static object Create(Type type,object arg1,object arg2,object arg3,object arg4,object arg5,object arg6,object arg7,object arg8,object arg9)
		{
			return CreateObject(type,new object[] { arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9 });
		}

		static object CreateObject(Type type,object[] arguments)
		{
			/*object result;
			if (RuntimeMethods.RuntimeMethodsExtender.DynamicCall(method,pis,target,arguments,out result))
				return result;*/

			//tady muzu vyresit rozdilny pocet argumentu zadanych a potrebnych
			int argsLength=arguments.Length;
			ConstructorInfo ci=Array.Find(type.GetConstructors(),x=>x.GetParameters().Length==argsLength);
			ParameterInfo[] pis=ci.GetParameters();

			argsLength=pis.Length;
			for (int a=0;a<argsLength;a++)
				arguments[a]=TranslateType(pis[a],arguments[a]);
			return ci.Invoke(arguments);
		}
		#endregion create

		internal static object TranslateType(ParameterInfo pi,object value)
		{
			Type t=pi.ParameterType;
			if (t==RuntimeMethods._objectType)
				return value;

			if (value is Delegate)
			{
				Delegate del=(Delegate)value;
				//return t.GetConstructors()[0].Invoke(new object[] { del.Target,del.Method.MethodHandle.GetFunctionPointer() });
				return Delegate.CreateDelegate(t,del.Target,del.Method);
			}

			return Convert.ChangeType(value,t);
		}

		static bool HaveOnlyObjects(ParameterInfo[] pis,Type retType)
		{
			if (retType!=RuntimeMethods._objectType)
				return false;
			foreach (ParameterInfo item in pis)
				if (item.ParameterType!=RuntimeMethods._objectType)
					return false;
			return true;
		}
	}
	#endregion DynamDelCalls

	#region ExternalVirtualObject
	internal class ExternalLibraryObject
	{
		internal Assembly _assembly;
	}

	internal class NamespaceObject:ExternalLibraryObject
	{
		internal string _name;
	}

	public class StaticObject
	{
		public Type Type;
	}

#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	public class ExternalMethodInfo
	{
		internal object Target;
		internal Type Type;
		internal string MethodName;
	}

	public delegate void ResolveExternalLibraryEventHandler(object sender,ResolveExternalLibraryEventArgs e);
	public class ResolveExternalLibraryEventArgs
	{
		public string LibraryName { get; internal set; }
		public string Predefinition { get; internal set; }
		public object Assembly { get; set; }
	}
	#endregion ExternalVirtualObject

	#region JsException
#if !DebugRuntime
	[DebuggerStepThrough]
#endif
	public class JsError:Exception
	{
		Exception _ex;
		int _number;
		string _stackTrace;

		public JsError(Exception ex):base(ex.Message,ex)
		{
			_ex=ex;
			JsError jsError=ex as JsError;
			if (jsError!=null)
				this._number=jsError._number;
		}

		public JsError(object number,object message)
		{
			_number=(int)number;
			_ex=new Exception((string)message) { Source="Jsil" };
			_stackTrace=new StackTrace(1).ToString();
		}

		public override IDictionary Data
		{
			get { return _ex.Data; }
		}

		public override Exception GetBaseException()
		{
			return _ex.GetBaseException();
		}

		public override string Message
		{
			get { return _ex.Message; }
		}

		public override string Source
		{
			get { return _ex.Source; }
			set { _ex.Source=value; }
		}

		public override string StackTrace
		{
			get { return _stackTrace??_ex.StackTrace; }
		}

		public string description
		{
			get { return this.Message; }
		}

		public string message
		{
			get { return this.Message; }
		}

		public int number
		{
			get { return _number; }
		}
	}
	#endregion JsException
}
